#include "Parser.h"
#include "Lex.h"
#include "Symbol.h"
#include "Interpreter.h"
#include "CompilierError.h"

CParser::CParser(std::shared_ptr<CLexer> lexer, std::shared_ptr<CInterpreter> vm) :
  m_Lexer(lexer),
  m_VM(vm),
  m_Done(false)
{
}

size_t CParser::GenerateCode(u32 op, u32 op_type, s64 op_val, const char* token_info)
{
  FILE* fp = fopen("bytecode.txt", "a+");
  fprintf(fp, "%s\t%08I64x\t%s\n", g_Opcode[op], op_val, token_info);
  fclose(fp);

  ByteCode bc = { (OPCODE)op, (ValueType)op_type };
  if (op_type == VT_NUMBER) {
    bc.v.n = op_val;
  } else {
    bc.v.s = (op_val==0)?"":(char*)op_val;
  }
  return m_VM->Generate(bc);
}

void CParser::FixJMP(size_t pc, size_t dst)
{
  m_VM->FixJMP(pc, dst);
}

void CParser::declaration_()
{
  m_Lexer->SkipToken();
  // var id1, id2 ... ;
  while (1) {
    TokenInfo token = m_Lexer->GetToken();
    if (token.type != __IDENTIFIER) {
      ReportError(token.line, "Invalid identifier found\n");
      break;
    }
    g_SymbolMgr.AddSymbol(token.value_s);
    m_Lexer->Expect(__IDENTIFIER);

    TokenInfo id = token;
    token = m_Lexer->GetToken();
    if (token.type == __SET) {
      // id = expr
      m_Lexer->Expect(__SET);
      expr_();
      GenerateCode(OP_SV, VT_NUMBER, g_SymbolMgr.GetSymbolIndex(id.value_s), id.value_s.c_str());
    }

    token = m_Lexer->GetToken();
    if (token.type == __SEMICOLON) {
      break;
    } else if (token.type != __COMMA) {
      ReportError(token.line, "Invalid identifier found\n");
      break;
    }
    m_Lexer->Expect(__COMMA);
  }
  m_Lexer->Expect(__SEMICOLON);
}

void CParser::function_params_()
{
  int param_count = 0;
  TokenInfo token = m_Lexer->GetToken();
  if (token.type == __RPAREN) {
    goto Exit;
  }

  // id1, id2, ... ;
  while (1) {
    expr_();

    param_count++;

    TokenInfo cur_token = m_Lexer->GetToken();
    if (cur_token.type == __RPAREN) {
      break;
    } else if (cur_token.type != __COMMA) {
      ReportError(cur_token.line, "Invalid identifier found\n");
    }
    m_Lexer->Expect(__COMMA);
  }

Exit:
  GenerateCode(OP_LDC, VT_NUMBER, param_count, "param count");
}

void CParser::function_params_def_()
{
  TokenInfo token = m_Lexer->GetToken();
  if (token.type == __RPAREN) {
    return;
  }

  // id1, id2, ... ;
  while (1) {
    TokenInfo cur_token = m_Lexer->GetToken();
    m_Lexer->Expect(__IDENTIFIER);

    //std::string name = m_FunctionName + "_" + cur_token.value_s;
    size_t index = g_SymbolMgr.AddSymbol(cur_token.value_s);
    GenerateCode(OP_SV, VT_NUMBER, (s64)index, cur_token.value_s.c_str());

    cur_token = m_Lexer->GetToken();
    if (cur_token.type == __RPAREN) {
      break;
    } else if (cur_token.type != __COMMA) {
      ReportError(cur_token.line, "Invalid identifier found\n");
    }
    m_Lexer->Expect(__COMMA);
  }
}

// function foo(id1, id2 ...)
// {
//   stmt ;
// }
void CParser::function_()
{
  size_t func_entry = GenerateCode(OP_JMP, VT_NUMBER, 0, "JMP");
  size_t func_begin = GenerateCode(OP_NOP, VT_NUMBER, 0, "NOP");

  m_Lexer->Expect(__FUNCTION);
  TokenInfo cur_token = m_Lexer->GetToken();
  m_FunctionName = cur_token.value_s;
  g_SymbolMgr.AddFunction(m_FunctionName, func_begin);
  m_Lexer->Expect(__IDENTIFIER);
  m_Lexer->Expect(__LPAREN);
  {
    function_params_def_();
  }
  m_Lexer->Expect(__RPAREN);

  m_Lexer->Expect(__LCURLY);
  {
    while (m_Lexer->GetToken().type != __RCURLY) {
      stmt_();
    }
  }
  m_Lexer->Expect(__RCURLY);
  m_FunctionName = "";

  size_t func_end = GenerateCode(OP_RET, VT_NUMBER, 0, "RET");
  size_t func_exit = GenerateCode(OP_NOP, VT_NUMBER, 0, "NOP");
  FixJMP(func_entry, func_exit);
}

void CParser::expr_()
{
  TokenInfo token = m_Lexer->GetToken();
  if (token.type == __SEMICOLON) {
    // Empty expression
    return;
  } else if (token.type == __IDENTIFIER) {
    // foo() or id2 = id1
    TokenInfo next_token = m_Lexer->NextToken();
    if (next_token.type == __LPAREN) {
      // id(param1, param2, param3, ...)  --  function call
      m_Lexer->Expect(__IDENTIFIER);
      m_Lexer->Expect(__LPAREN);
      {
        function_params_();
      }
      m_Lexer->Expect(__RPAREN);

      GenerateCode(OP_CALL, VT_STRING, (s64)token.value_s.c_str(), token.value_s.c_str());
      return;
    } else if (token_is_set(next_token)) {
      // id = expr | id += expr  --  set
      m_Lexer->Expect(__IDENTIFIER);
      m_Lexer->SkipToken();
      expr_();

      GenerateCode(OP_SV, VT_NUMBER, g_SymbolMgr.GetSymbolIndex(token.value_s), token.value_s.c_str());
      return;
    }
  }
  term_();
  more_terms_();
}

void CParser::term_()
{
  factor_();
  more_factors_();
}

void CParser::more_terms_()
{
  TokenInfo token = m_Lexer->GetToken();
  if (token.type == __ADD || token.type == __SUB) {
    m_Lexer->SkipToken();
    term_();
    more_terms_();

    OPCODE op = (token.type == __ADD) ? OP_ADD : OP_SUB;
    GenerateCode(op, VT_NUMBER, 0, "OP");
  }
}

void CParser::factor_()
{
  TokenInfo token = m_Lexer->GetToken();
  if (token.type == __LPAREN) {
    // '(' expr ')'
    m_Lexer->Expect(__LPAREN);
    {
      expr_();
    }
    m_Lexer->Expect(__RPAREN);
    return;
  }
  if (token.type == __IDENTIFIER || token.type == __NUMBER || token.type == __STRING) {
    m_Lexer->SkipToken();

    switch (token.type)
    {
    case __IDENTIFIER:
      GenerateCode(OP_LD, VT_NUMBER, g_SymbolMgr.GetSymbolIndex(token.value_s), token.value_s.c_str());
      break;
    case __NUMBER:
      GenerateCode(OP_LDC, VT_NUMBER, token.value_n, "number");
      break;
    case __STRING:
      GenerateCode(OP_LDC, VT_STRING, (s64)token.value_s.c_str(), token.value_s.c_str());
      break;
    }
    return;
  }
  ReportError(token.line, "Invalid factor\n");
}

void CParser::more_factors_()
{
  TokenInfo token = m_Lexer->GetToken();
  if (token.type == __MULT || token.type == __DIV || token.type == __MOD) {
    m_Lexer->SkipToken();
    factor_();
    more_factors_();

    OPCODE op = (token.type == __MULT) ? OP_MUL : ((token.type == __DIV) ? OP_DIV : OP_MOD);
    GenerateCode(op, 0, 0, "OP");
  }
}

void CParser::if_()
{
  // if '(' expr ')' '{' stmt '}'
  m_Lexer->Expect(__IF);
  m_Lexer->Expect(__LPAREN);
  {
    expr_();
    TokenInfo token = m_Lexer->GetToken();
    if (token_is_comp(token)) {
      m_Lexer->SkipToken();
      expr_();
      GenerateCode(OP_CMP, VT_NUMBER, token.type, "CMP");
    }
  }
  m_Lexer->Expect(__RPAREN);

  size_t pc_if = GenerateCode(OP_JCC, VT_NUMBER, 0, "JCC");

  m_Lexer->Expect(__LCURLY);
  {
    do {
      stmt_();
    } while (m_Lexer->GetToken().type != __RCURLY);
  }
  m_Lexer->Expect(__RCURLY);

  size_t pc_else = GenerateCode(OP_JMP, VT_NUMBER, 0, "JMP");

  size_t dst_if = GenerateCode(OP_NOP, VT_NUMBER, 0, "NOP");
  FixJMP(pc_if, dst_if);

  // ['else' '{' stmt '}']
  if (m_Lexer->GetToken().type == __ELSE) {
    m_Lexer->Expect(__ELSE);
    stmt_();
  }
  size_t dst_else = GenerateCode(OP_NOP, VT_NUMBER, 0, "NOP");
  FixJMP(pc_else, dst_else);
}

void CParser::while_()
{
  size_t dst_begin = GenerateCode(OP_NOP, VT_NUMBER, 0, "NOP");

  // while '(' expr ')' '{' stmt '}'
  m_Lexer->Expect(__WHILE);
  m_Lexer->Expect(__LPAREN);
  {
    expr_();
    TokenInfo token = m_Lexer->GetToken();
    if (token_is_comp(token)) {
      m_Lexer->SkipToken();
      expr_();
      GenerateCode(OP_CMP, VT_NUMBER, token.type, "CMP");
    }
  }
  m_Lexer->Expect(__RPAREN);

  size_t pc_while = GenerateCode(OP_JCC, VT_NUMBER, 0, "JCC");

  m_Lexer->Expect(__LCURLY);
  {
    do {
      stmt_();
    } while (m_Lexer->GetToken().type != __RCURLY);
  }
  m_Lexer->Expect(__RCURLY);
  GenerateCode(OP_JMP, VT_NUMBER, dst_begin, "JMP");

  size_t dst_end = GenerateCode(OP_NOP, VT_NUMBER, 0, "NOP");
  FixJMP(pc_while, dst_end);
}

void CParser::return_()
{
  m_Lexer->Expect(__RETURN);
  {
    TokenInfo token = m_Lexer->GetToken();
    if (token.type != __SEMICOLON) {
      expr_();
    }
  }
  m_Lexer->Expect(__SEMICOLON);
}

void CParser::stmt_()
{
  TokenInfo token = m_Lexer->GetToken();
  if (token.type == __LCURLY) {
    m_Lexer->Expect(__LCURLY);
    {
      stmt_();
    }
    m_Lexer->Expect(__RCURLY);
  } else if (token.type == __VAR) {
    declaration_();
  } else if (token.type == __IF) {
    if_();
  } else if (token.type == __WHILE) {
    while_();
  } else if (token.type == __RETURN) {
    return_();
  } else {
    expr_();
    m_Lexer->Expect(__SEMICOLON);
  }
}

void CParser::Parse()
{
  while (1) {
    TokenInfo token = m_Lexer->GetToken();
    if (token.type == __EOF) {
      break;
    }
    if (token.type == __FUNCTION) {
      function_();
    } else {
      stmt_();
    }
  }
}
